package server;
import java.io.EOFException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;

import toolkit.Debug;
import toolkit.Global;
import toolkit.Parse;

/**
 * The class which will handle all incoming clients.
 */
public class InitializeServer extends Thread
{
	
	/** The port on which the server socket will be bind and which the clients need to connect to. */
	private static final int SERVER_SOCKET_PORT = 2005;
	
	/** Should the server still accept clients? */
	boolean listening = true;
	
	/**
	 * Instantiates a new initialize server.
	 */
	public InitializeServer()
	{
		super("ServerSettings");
	}
	
	// Stop accepting client requests.
	/**
	 * Stop listening.
	 */
	public void stopListening()
	{
		listening = false;
	}
	
	public void run()
	{
		// The thread that will handle every client, so multiply clients
		// can make requests to our server.
		class HandleClient extends Thread
		{
			private Socket socket;
			
			public HandleClient(Socket socket)
			{
				this.socket = socket;
			}
			
			public void run()
			{
				// The stream containing the requests of the client.
				ObjectInputStream input = null;
				
				// The stream containing the responses of the server. 
				ObjectOutputStream output = null;
				
				try
				{
					// The current request of the client.
					String request;
					
					input = new ObjectInputStream(socket.getInputStream());
					
					// The response of the current request.
					Object response;
					
					output = new ObjectOutputStream(socket.getOutputStream());
					
					try
					{
						// Keep trying to fetch requests until there are none left.
						while (true)
						{
							request = (String) input.readObject();
							
							response = null;
							
							// If the server understands the request, send a matching response.
							if (request.equals("getCodebase"))
							{
								response = Global.getCodeBase();
							}
							else if (request.equals("getRegistryPort"))
							{
								response = new Integer(rmi.Server.REGISTRY_PORT);
							}
							
							output.writeObject(response);
						}
					}
					catch (EOFException e) {}
					
					output.flush();
				}
				catch (Exception e)
				{
					Debug.log(e);
					
					// Something went wrong trying to give responses to the client.
					// This will however not crash the client application, but they will
					// receive null values for each requests instead.
				}
				
				if (input != null)
				{
					try
					{
						input.close();
					}
					catch (Exception e)
					{
						Debug.log(e);
					}
				}
				
				if (output != null)
				{
					try
					{
						output.close();
					}
					catch (Exception e)
					{
						Debug.log(e);
					}
				}
				
				if (socket != null)
				{
					try
					{
						socket.close();
					}
					catch (Exception e)
					{
						Debug.log(e);
					}
				}
			}
		}
		
		// The socket of the server.
		ServerSocket serverSocket = null;
		
		try
		{
			serverSocket = new ServerSocket(SERVER_SOCKET_PORT);
			
			// Keep handle clients until the server application is turned off.
			while (listening)
			{
				new HandleClient(serverSocket.accept()).start();
			}
		}
		catch (BindException e)
		{
			Server.getLogger().log(Level.SEVERE, "The server could not be bind to the given socket.\n" +
					"The server is probably already running.", e);
		}
		catch (Exception e)
		{
			Debug.log(e);
		}
		
		// Close the server socket.
		if (serverSocket != null)
		{
			try
			{
				serverSocket.close();
			}
			catch (Exception e)
			{
				Debug.log(e);
			}
		}
	}
}
